package com.nulldev.util.internal.backport.httpclient_rw;

import java.io.IOException;
import java.net.Authenticator;
import java.net.CookieHandler;
import java.net.ProxySelector;
import java.time.Duration;
import java.util.concurrent.Executor;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;

import com.nulldev.util.internal.backport.concurrency9.concurrent.CompletableFuture;
import com.nulldev.util.internal.backport.httpclient_rw.HttpResponse.BodyHandler;
import com.nulldev.util.internal.backport.httpclient_rw.HttpResponse.PushPromiseHandler;
import com.nulldev.util.internal.backport.httpclient_rw.backports.BackportedReference;
import com.nulldev.util.internal.backport.httpclient_rw.impl.common.OperationTrackers.Trackable;
import com.nulldev.util.internal.backport.httpclient_rw.impl.common.OperationTrackers.Tracker;
import com.nulldev.util.internal.backport.optionals.Optional;

/**
 * An HttpClientFacade is a simple class that wraps an HttpClient implementation
 * and delegates everything to its implementation delegate.
 */
final class HttpClientFacade extends HttpClient implements Trackable {

	final HttpClientImpl impl;

	/**
	 * Creates an HttpClientFacade.
	 */
	HttpClientFacade(HttpClientImpl impl) {
		this.impl = impl;
	}

	@Override // for tests
	public Tracker getOperationsTracker() {
		return impl.getOperationsTracker();
	}

	@Override
	public Optional<CookieHandler> cookieHandler() {
		return impl.cookieHandler();
	}

	@Override
	public Optional<Duration> connectTimeout() {
		return impl.connectTimeout();
	}

	@Override
	public Redirect followRedirects() {
		return impl.followRedirects();
	}

	@Override
	public Optional<ProxySelector> proxy() {
		return impl.proxy();
	}

	@Override
	public SSLContext sslContext() {
		return impl.sslContext();
	}

	@Override
	public SSLParameters sslParameters() {
		return impl.sslParameters();
	}

	@Override
	public Optional<Authenticator> authenticator() {
		return impl.authenticator();
	}

	@Override
	public HttpClient.Version version() {
		return impl.version();
	}

	@Override
	public Optional<Executor> executor() {
		return impl.executor();
	}

	@Override
	public <T> HttpResponse<T> send(HttpRequest req, HttpResponse.BodyHandler<T> responseBodyHandler) throws IOException, InterruptedException {
		try {
			return impl.send(req, responseBodyHandler);
		} finally {
			BackportedReference.reachabilityFence(this);
		}
	}

	@Override
	public <T> CompletableFuture<HttpResponse<T>> sendAsync(HttpRequest req, HttpResponse.BodyHandler<T> responseBodyHandler) {
		try {
			return impl.sendAsync(req, responseBodyHandler);
		} finally {
			BackportedReference.reachabilityFence(this);
		}
	}

	@Override
	public <T> CompletableFuture<HttpResponse<T>> sendAsync(HttpRequest req, BodyHandler<T> responseBodyHandler, PushPromiseHandler<T> pushPromiseHandler) {
		try {
			return impl.sendAsync(req, responseBodyHandler, pushPromiseHandler);
		} finally {
			BackportedReference.reachabilityFence(this);
		}
	}

	@Override
	public WebSocket.Builder newWebSocketBuilder() {
		try {
			return impl.newWebSocketBuilder();
		} finally {
			BackportedReference.reachabilityFence(this);
		}
	}

	@Override
	public String toString() {
		// Used by tests to get the client's id.
		return impl.toString();
	}
}